package com.huang.wishstar.utils;

import com.google.common.collect.Lists;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;


import static java.util.Calendar.DAY_OF_WEEK;

/**
 *
 * java1.8 的新特性，解决SimpleDateFormat的线程问题<br>
 * <li>Instant代替 Date，</li>
 * <li>LocalDateTime代替 Calendar，</li>
 * <li>DateTimeFormatter 代替 SimpleDateFormat.</li> 注意：如果是共享变量，则可能会出现线程问题。<br>
 *
 */
public class DateUtil {
    // 时间元素
    private static final String YEAR = "year";
    private static final String MONTH = "month";
    private static final String WEEK = "week";
    private static final String DAY = "day";
    private static final String HOUR = "hour";
    private static final String MINUTE = "minute";
    private static final String SECOND = "second";
    // 星期元素
    private static final String MONDAY = "MONDAY";// 星期一
    private static final String TUESDAY = "TUESDAY";// 星期二
    private static final String WEDNESDAY = "WEDNESDAY";// 星期三
    private static final String THURSDAY = "THURSDAY";// 星期四
    private static final String FRIDAY = "FRIDAY";// 星期五
    private static final String SATURDAY = "SATURDAY";// 星期六
    private static final String SUNDAY = "SUNDAY";// 星期日

    // 根据指定格式显示日期和时间
    /** yyyy-MM-dd */
    private static final DateTimeFormatter yyyyMMdd_EN = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    /** yyyy-MM-dd HH */
    private static final DateTimeFormatter yyyyMMddHH_EN = DateTimeFormatter.ofPattern("yyyy-MM-dd HH");
    /** yyyy-MM-dd HH:mm */
    private static final DateTimeFormatter yyyyMMddHHmm_EN = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    /** yyyy-MM-dd HH:mm:ss */
    private static final DateTimeFormatter yyyyMMddHHmmss_EN = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    /** HH:mm:ss */
    private static final DateTimeFormatter HHmmss_EN = DateTimeFormatter.ofPattern("HH:mm:ss");
    /** yyyy年MM月dd日 */
    private static final DateTimeFormatter yyyyMMdd_CN = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
    /** yyyy年MM月dd日HH时 */
    private static final DateTimeFormatter yyyyMMddHH_CN = DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时");
    /** yyyy年MM月dd日HH时mm分 */
    private static final DateTimeFormatter yyyyMMddHHmm_CN = DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分");
    /** yyyy年MM月dd日HH时mm分ss秒 */
    private static final DateTimeFormatter yyyyMMddHHmmss_CN = DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒");
    /** HH时mm分ss秒 */
    private static final DateTimeFormatter HHmmss_CN = DateTimeFormatter.ofPattern("HH时mm分ss秒");

    // 本地时间显示格式：区分中文和外文显示
    private static final DateTimeFormatter shotDate = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
    private static final DateTimeFormatter fullDate = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
    private static final DateTimeFormatter longDate = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG);
    private static final DateTimeFormatter mediumDate = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);

    /**
     * 以下为获取当前日期的方法
     */

    /**
     * 获取当前日期
     * @return yyyy-MM-dd
     */
    public static String getNowDate_EN() {
        return String.valueOf(LocalDate.now());
    }

    /**
     * 获取当前日期
     * @return 字符串yyyy-MM-dd HH:mm:ss
     */
    public static String getNowTime_EN() {
        return LocalDateTime.now().format(yyyyMMddHHmmss_EN);
    }

    /** 获取当前时间（yyyy-MM-dd HH） */
    public static String getNowTime_EN_yMdH() {
        return LocalDateTime.now().format(yyyyMMddHH_EN);
    }

    /** 获取当前时间（yyyy年MM月dd日） */
    public static String getNowTime_CN_yMdH() {
        return LocalDateTime.now().format(yyyyMMddHH_CN);
    }

    /** 获取当前时间（yyyy-MM-dd HH:mm） */
    public static String getNowTime_EN_yMdHm() {
        return LocalDateTime.now().format(yyyyMMddHHmm_EN);
    }

    /** 获取当前时间（yyyy年MM月dd日HH时mm分） */
    public static String getNowTime_CN_yMdHm() {
        return LocalDateTime.now().format(yyyyMMddHHmm_CN);
    }

    /** 获取当前时间（HH时mm分ss秒） */
    public static String getNowTime_CN_HHmmss() {
        return LocalDateTime.now().format(HHmmss_CN);
    }

    /**
     * 根据日期格式，获取当前时间
     * @param formatStr 日期格式<br>
     *        <li>yyyy</li>
     *        <li>yyyy-MM-dd</li>
     *        <li>yyyy-MM-dd HH:mm:ss</li>
     *        <li>HH:mm:ss</li>
     * @return
     */
    public static String getTime(String formatStr) {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(formatStr));
    }

    /**
     * 获取中文的当前日期
     * @return yyyy年mm月dd日
     */
    public static String getNowDate_CN() {
        return LocalDate.now().format(yyyyMMdd_CN);
    }

    /**
     * 获取中文当前时间
     * @return yyyy年MM月dd日HH时mm分ss秒
     */
    public static String getNowTime_CN() {
        return LocalDateTime.now().format(yyyyMMddHHmmss_CN);
    }

    /**
     * 简写本地当前日期：yy-M-dd<br>
     * 例如：19-3-30为2019年3月30日
     * @return 字符串yy-M-dd
     */
    public static String getNowLocalTime_shot() {
        return LocalDateTime.now().format(shotDate);
    }

    /**
     * 根据当地日期显示格式：yyyy年M月dd日 星期？（中国）
     *
     * @return 形如：2019年3月30日 星期六
     */
    public static String getNowLocalTime_full() {
        return LocalDateTime.now().format(fullDate);
    }

    /**
     * 根据当地显示日期格式：yyyy年M月dd日（中国）
     *
     * @return 形如 2019年3月30日
     */
    public static String getNowLocalTime_long() {
        return LocalDateTime.now().format(longDate);
    }

    /**
     * 根据当地显示日期格式：yyyy-M-dd（中国）
     * @return 形如：2019-3-30
     */
    public static String getNowLocalTime_medium() {
        return LocalDateTime.now().format(mediumDate);
    }

    /**
     * 获取当前日期的节点时间（年，月，周，日，时，分，秒）
     * @param node 日期中的节点元素（年，月，周，日，时，分，秒）
     * @return 节点数字，如创建此方法的时间：年 2019，月 3，日 30，周 6
     */
    public static Integer getNodeTime(String node) {
        LocalDateTime today = LocalDateTime.now();
        Integer resultNode = null;
        switch (node) {
            case YEAR:
                resultNode = today.getYear();
                break;
            case MONTH:
                resultNode = today.getMonthValue();
                break;
            case WEEK:
                resultNode = transformWeekEN2Num(String.valueOf(today.getDayOfWeek()));
                break;
            case DAY:
                resultNode = today.getDayOfMonth();
                break;
            case HOUR:
                resultNode = today.getHour();
                break;
            case MINUTE:
                resultNode = today.getMinute();
                break;
            case SECOND:
                resultNode = today.getSecond();
                break;
            default:
                // 当前日期是当前年的第几天。例如：2019/1/3是2019年的第三天
                resultNode = today.getDayOfYear();
                break;
        }
        return resultNode;
    }



    /**
     * 以下为时间间隔相关的方法，比如多少天月年之后的日期，相隔多少天，
     */
    /**
     * 计算两个日期字符串之间相差多少个周期（天，月，年）
     *
     * @param date1 yyyy-MM-dd
     * @param date2 yyyy-MM-dd
     * @param node 三者之一:(day，month,year)
     * @return 相差多少周期
     */
    public static int periodCount(String date1, String date2, String node) {
        date1 = date1.trim();
        date2 = date2.trim();
        if (DAY.equals(node)) {
            return Period.between(LocalDate.parse(date1), LocalDate.parse(date2)).getDays();
        } else if (MONTH.equals(node)) {
            return Period.between(LocalDate.parse(date1), LocalDate.parse(date2)).getMonths();
        } else if (YEAR.equals(node)) {
            return Period.between(LocalDate.parse(date1), LocalDate.parse(date2)).getYears();
        } else {
            return 0;
        }
    }
    /**
     * 获取当前日期之后（之后）的节点事件<br>
     * <ul>
     * 比如当前时间为：2019-03-30 10:20:30
     * </ul>
     * <li>node="hour",num=5L:2019-03-30 15:20:30</li>
     * <li>node="day",num=1L:2019-03-31 10:20:30</li>
     * <li>node="year",num=1L:2020-03-30 10:20:30</li>
     *
     * @param node 节点元素（“year”,"month","week","day","huor","minute","second"）
     * @param num 第几天（+：之后，-：之前）
     * @return 之后或之后的日期
     */
    public static String getAfterOrPreNowTime(String node, Long num) {
        LocalDateTime now = LocalDateTime.now();
        if (HOUR.equals(node)) {
            return now.plusHours(num).format(yyyyMMddHHmmss_EN);
        } else if (DAY.equals(node)) {
            return now.plusDays(num).format(yyyyMMddHHmmss_EN);
        } else if (WEEK.equals(node)) {
            return now.plusWeeks(num).format(yyyyMMddHHmmss_EN);
        } else if (MONTH.equals(node)) {
            return now.plusMonths(num).format(yyyyMMddHHmmss_EN);
        } else if (YEAR.equals(node)) {
            return now.plusYears(num).format(yyyyMMddHHmmss_EN);
        } else if (MINUTE.equals(node)) {
            return now.plusMinutes(num).format(yyyyMMddHHmmss_EN);
        } else if (SECOND.equals(node)) {
            return now.plusSeconds(num).format(yyyyMMddHHmmss_EN);
        } else {
            return "Node is Error!";
        }
    }

    /**
     * 获取与当前日期相距num个之后（之前）的日期<br>
     * <ul>
     * 比如当前时间为：2019-03-30 10:20:30的格式日期
     * <li>node="hour",num=5L:2019-03-30 15:20:30</li>
     * <li>node="day",num=1L:2019-03-31 10:20:30</li>
     * <li>node="year",num=1L:2020-03-30 10:20:30</li>
     * </ul>
     *
     * @param dtf 格式化当前时间格式（dtf = yyyyMMddHHmmss_EN）
     * @param node 节点元素（“year”,"month","week","day","huor","minute","second"）
     * @param num （+：之后，-：之前）
     * @return 之后之前的日期
     */
    public static String getAfterOrPreNowTimePlus(DateTimeFormatter dtf, String node, Long num) {
        LocalDateTime now = LocalDateTime.now();
        if (HOUR.equals(node)) {
            return now.plusHours(num).format(dtf);
        } else if (DAY.equals(node)) {
            return now.plusDays(num).format(dtf);
        } else if (WEEK.equals(node)) {
            return now.plusWeeks(num).format(dtf);
        } else if (MONTH.equals(node)) {
            return now.plusMonths(num).format(dtf);
        } else if (YEAR.equals(node)) {
            return now.plusYears(num).format(dtf);
        } else if (MINUTE.equals(node)) {
            return now.plusMinutes(num).format(dtf);
        } else if (SECOND.equals(node)) {
            return now.plusSeconds(num).format(dtf);
        } else {
            return "Node is Error!";
        }
    }

    /**
     * 当前时间的hour，minute，second之后（之前）的时刻
     *
     * @param node 时间节点元素（hour，minute，second）
     * @param num 之后（之后）多久时，分，秒（+：之后，-：之前）
     * @return HH:mm:ss 字符串
     */
    public static String getAfterOrPreNowTimeSimp(String node, Long num) {
        LocalTime now = LocalTime.now();
        if (HOUR.equals(node)) {
            return now.plusHours(num).format(HHmmss_EN);
        } else if (MINUTE.equals(node)) {
            return now.plusMinutes(num).format(HHmmss_EN);
        } else if (SECOND.equals(node)) {
            return now.plusSeconds(num).format(HHmmss_EN);
        } else {
            return "Node is Error!";
        }
    }


    /**
     * 获取当前日期第index日之后(之前)的日期（yyyy-MM-dd）
     *
     * @param index 第index天
     * @return 日期字符串：yyyy-MM-dd
     */
    public static String getAfterOrPreDayDate(int index) {
        return LocalDate.now().plus(index, ChronoUnit.DAYS).format(yyyyMMdd_EN);
    }

    /**
     * 获取当前日期第index周之前（之后）的日期（yyyy-MM-dd）
     *
     * @param index 第index周（+：之后，-：之前）
     * @return 日期字符串：yyyy-MM-dd
     */
    public static String getAfterOrPreWeekDate(int index) {
        return LocalDate.now().plus(index, ChronoUnit.WEEKS).format(yyyyMMdd_EN);
    }

    /**
     * 获取当前日期第index月之前（之后）的日期（yyyy-MM-dd）
     *
     * @param index 第index月（+：之后，-：之前）
     * @return 日期字符串：yyyy-MM-dd
     */
    public static String getAfterOrPreMonthDate(int index) {
        return LocalDate.now().plus(index, ChronoUnit.MONTHS).format(yyyyMMdd_EN);
    }

    /**
     * 获取当前日期第index年之前（之后）的日期（yyyy-MM-dd）
     *
     * @param index 第index年（+：之后，-：之前）
     * @return 日期字符串：yyyy-MM-dd
     */
    public static String getAfterOrPreYearDate(int index) {
        return LocalDate.now().plus(index, ChronoUnit.YEARS).format(yyyyMMdd_EN);
    }

    /**
     * 获取指定日期之前之后的第index的日，周，月，年的日期
     *
     * @param date 指定日期格式：yyyy-MM-dd
     * @param node 时间节点元素（日周月年）
     * @param index 之前之后第index个日期
     * @return yyyy-MM-dd 日期字符串
     */
    public static String getAfterOrPreDate(String date, String node, int index) {
        date = date.trim();
        if (DAY.equals(node)) {
            return LocalDate.parse(date).plus(index, ChronoUnit.DAYS).format(yyyyMMdd_EN);
        } else if (WEEK.equals(node)) {
            return LocalDate.parse(date).plus(index, ChronoUnit.WEEKS).format(yyyyMMdd_EN);
        } else if (MONTH.equals(node)) {
            return LocalDate.parse(date).plus(index, ChronoUnit.MONTHS).format(yyyyMMdd_EN);
        } else if (YEAR.equals(node)) {
            return LocalDate.parse(date).plus(index, ChronoUnit.YEARS).format(yyyyMMdd_EN);
        } else {
            return "Wrong date format!";
        }
    }


    /**
     * 切割日期。按照周期切割成小段日期段。例如： <br>
     *
     * @param startDate 开始日期（yyyy-MM-dd）
     * @param endDate 结束日期（yyyy-MM-dd）
     * @param period 周期（天，周，月，年）
     * @return 切割之后的日期集合
     * @example
     *          <li>startDate="2019-02-28",endDate="2019-03-05",period="day"</li>
     *          <li>结果为：[2019-02-28, 2019-03-01, 2019-03-02, 2019-03-03, 2019-03-04, 2019-03-05]</li><br>
     *          <li>startDate="2019-02-28",endDate="2019-03-25",period="week"</li>
     *          <li>结果为：[2019-02-28,2019-03-06, 2019-03-07,2019-03-13, 2019-03-14,2019-03-20,
     *          2019-03-21,2019-03-25]</li><br>
     *          <li>startDate="2019-02-28",endDate="2019-05-25",period="month"</li>
     *          <li>结果为：[2019-02-28,2019-02-28, 2019-03-01,2019-03-31, 2019-04-01,2019-04-30,
     *          2019-05-01,2019-05-25]</li><br>
     *          <li>startDate="2019-02-28",endDate="2020-05-25",period="year"</li>
     *          <li>结果为：[2019-02-28,2019-12-31, 2020-01-01,2020-05-25]</li><br>
     */
    public static List<String> getPieDateRange(String startDate, String endDate, String period) {
        List<String> result = Lists.newArrayList();
        LocalDate end = LocalDate.parse(endDate, yyyyMMdd_EN);
        LocalDate start = LocalDate.parse(startDate, yyyyMMdd_EN);
        LocalDate tmp = start;
        switch (period) {
            case DAY:
                while (start.isBefore(end) || start.isEqual(end)) {
                    result.add(start.toString());
                    start = start.plusDays(1);
                }
                break;
            case WEEK:
                while (tmp.isBefore(end) || tmp.isEqual(end)) {
                    if (tmp.plusDays(6).isAfter(end)) {
                        result.add(tmp.toString() + "," + end);
                    } else {
                        result.add(tmp.toString() + "," + tmp.plusDays(6));
                    }
                    tmp = tmp.plusDays(7);
                }
                break;
            case MONTH:
                while (tmp.isBefore(end) || tmp.isEqual(end)) {
                    LocalDate lastDayOfMonth = tmp.with(TemporalAdjusters.lastDayOfMonth());
                    if (lastDayOfMonth.isAfter(end)) {
                        result.add(tmp.toString() + "," + end);
                    } else {
                        result.add(tmp.toString() + "," + lastDayOfMonth);
                    }
                    tmp = lastDayOfMonth.plusDays(1);
                }
                break;
            case YEAR:
                while (tmp.isBefore(end) || tmp.isEqual(end)) {
                    LocalDate lastDayOfYear = tmp.with(TemporalAdjusters.lastDayOfYear());
                    if (lastDayOfYear.isAfter(end)) {
                        result.add(tmp.toString() + "," + end);
                    } else {
                        result.add(tmp.toString() + "," + lastDayOfYear);
                    }
                    tmp = lastDayOfYear.plusDays(1);
                }
                break;
            default:
                break;
        }
        return result;
    }


    /**
     * 获取下一个星期的日期
     *
     * @param curDay yyyy-MM-dd
     * @param dayOfWeek monday:1~sunday:7
     * @param isContainCurDay 是否包含当天，true：是，false：不包含
     * @return 日期（yyyy-MM-dd）
     */
    public static String getNextWeekDate(String curDay, int dayOfWeek, boolean isContainCurDay) {
        dayOfWeek = dayOfWeek < 1 || dayOfWeek > 7 ? 1 : dayOfWeek;
        if (isContainCurDay) {
            return LocalDate.parse(curDay).with(TemporalAdjusters.nextOrSame(DayOfWeek.of(dayOfWeek))).toString();
        } else {
            return LocalDate.parse(curDay).with(TemporalAdjusters.next(DayOfWeek.of(dayOfWeek))).toString();
        }
    }

    /**
     * 获取上一个星期的日期
     *
     * @param curDay 指定日期（yyyy-MM-dd）
     * @param dayOfWeek 数字范围（monday:1~sunday:7）
     * @param isCurDay 是否包含当天，true：是，false：不包含
     * @return 日期（yyyy-MM-dd）
     */
    public static String getPreWeekDate(String curDay, int dayOfWeek, boolean isCurDay) {
        dayOfWeek = dayOfWeek < 1 || dayOfWeek > 7 ? 1 : dayOfWeek;
        if (isCurDay) {
            return LocalDate.parse(curDay).with(TemporalAdjusters.previousOrSame(DayOfWeek.of(dayOfWeek))).toString();
        } else {
            return LocalDate.parse(curDay).with(TemporalAdjusters.previous(DayOfWeek.of(dayOfWeek))).toString();
        }
    }

    /**
     * 获取指定日期当月的最后或第一个星期日期
     *
     * @param curDay 指定日期（yyyy-MM-dd）
     * @param dayOfWeek 周几（1~7）
     * @param lastOrFirst true：最后一个，false本月第一个
     * @return 日期（yyyy-MM-dd）
     */
    public static String getFirstOrLastWeekDate(String curDay, int dayOfWeek, boolean lastOrFirst) {
        dayOfWeek = dayOfWeek < 1 || dayOfWeek > 7 ? 1 : dayOfWeek;
        if (lastOrFirst) {
            return LocalDate.parse(curDay).with(TemporalAdjusters.lastInMonth(DayOfWeek.of(dayOfWeek))).toString();
        } else {
            return LocalDate.parse(curDay).with(TemporalAdjusters.firstInMonth(DayOfWeek.of(dayOfWeek))).toString();
        }
    }
    //以上为最初的工具类，
    /**
     * 下面为与星期相关的方法
     */

    /**
     * 将英文星期转换成数字
     *
     * @param enWeek 英文星期
     * @return int，如果数字小于0，则检查，看是否输入错误 or 入参为null
     */
    public static int transformWeekEN2Num(String enWeek) {
        if (MONDAY.equals(enWeek)) {
            return 1;
        } else if (TUESDAY.equals(enWeek)) {
            return 2;
        } else if (WEDNESDAY.equals(enWeek)) {
            return 3;
        } else if (THURSDAY.equals(enWeek)) {
            return 4;
        } else if (FRIDAY.equals(enWeek)) {
            return 5;
        } else if (SATURDAY.equals(enWeek)) {
            return 6;
        } else if (SUNDAY.equals(enWeek)) {
            return 7;
        } else {
            return -1;
        }
    }
    /**
     * 判断今天是周几
     * @param 传入String
     * @return int 周一-周日对应1-7
     */

    /**
     * 获取指定日期所属周的周一的日期
     * @param localDate
     * @return
     */
    public static LocalDateTime getMondayForThisWeek(LocalDate localDate) {
        LocalDateTime monday = LocalDateTime.of(localDate, LocalTime.MIN).with(DayOfWeek.MONDAY);
        return monday;
    }

    /**
     * 获取指定日期所属周的周日的日期
     * @param localDate
     * @return
     */
    public static LocalDateTime getSundayForThisWeek(LocalDate localDate) {
        LocalDateTime sunday = LocalDateTime.of(localDate, LocalTime.MIN).with(DayOfWeek.SUNDAY);
        return sunday;
    }

    /**
     * 获取指定日期所属周的下周一的日期
     * @param localDate
     * @return
     */
    public static LocalDateTime getMondayForNextWeek(LocalDate localDate) {
        LocalDateTime monday = LocalDateTime.of(localDate, LocalTime.MIN).plusWeeks(1).with(DayOfWeek.MONDAY);
        return monday;
    }

    /**
     * 获取指定日期所属周的下周日的日期
     * @param localDate
     * @return
     */
    public static LocalDateTime getSundayForNextWeek(LocalDate localDate) {
        LocalDateTime sunday = LocalDateTime.of(localDate, LocalTime.MIN).plusWeeks(1).with(DayOfWeek.SUNDAY);
        return sunday;
    }


    /**
     * 以下都为LocalDate、LocalDateTime、Date、String、Long之间的转换
     */

    /**
     * 指定格式为"yyyy-MM-dd HH:mm:ss"的字符串时间转化为LocalDateTime类型
     * @param dateStr
     * @return
     */
    public static LocalDateTime getLocalDateTimeFromString(String dateStr) {
        LocalDateTime localDateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        return localDateTime;
    }

    /**
     * LocalDateTime类型转化为格式为"yyyy-MM-dd HH:mm:ss"的字符串时间类型
     * @param localDateTime
     * @return
     */
    public static String getStringFromLocalDateTime(LocalDateTime localDateTime) {
        String localDateTimeStr = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        return localDateTimeStr;
    }

    /**
     * Date类型时间转化为LocalDateTime类型
     * @param date
     * @return
     */
    public static LocalDateTime getLocalDateTimeFromDate(Date date) {
        LocalDateTime localDateTime = date.toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime();
        return localDateTime;
    }

    /**
     * LocalDateTime类型转化为Date类型时间
     * @param localDateTime
     * @return
     */
    public static Date getDateFromLocalDateTime(LocalDateTime localDateTime) {
        Date date = Date.from(localDateTime.toInstant(ZoneOffset.of("+8")));
        return date;
    }
    /**
     * 传入的时间字符串String按照所给的格式转换成Date
     */
    public static Date getDateFromString(String dateStr,String formaterString){
        Date date = null;
        SimpleDateFormat formater = new SimpleDateFormat();formater.applyPattern(formaterString);
        try {
            date = formater.parse(dateStr);
        }
        catch (ParseException e) {
            e.printStackTrace( );
        }
        return date;
    }

    /**
     * 传入的Date时间以想要的格式转换成字符串
     */
    public static String getStringFromDate(Date date,String formaterString) {
        String time;
        SimpleDateFormat formater = new SimpleDateFormat();
        formater.applyPattern(formaterString);
        time = formater.format(date);
        return time;
    }

    /**
     * 时间戳(毫秒)转化为LocalDateTime格式
     * @param timestamp
     * @return
     */
    public static LocalDateTime getLocalDateTimeFromTimestamp(Long timestamp) {
        LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(timestamp/1000, 0, ZoneOffset.ofHours(8));
        return localDateTime;
    }

    /**
     * LocalDateTime格式转化为时间戳(毫秒)
     */
    public static Long getTimestampFromLocalDateTime(LocalDateTime localDateTime) {
        Long timestamp = localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
        return timestamp;
    }

    /**
     * 时间区间的相关方法，比如一天的最早，一天的最晚，一个日期是否在某个区间里
     */

    /**
     * 获取指定时间的00:00:00
     * @param localDateTime
     */
    public static LocalDateTime getLocalDateTimeForBegin(LocalDateTime localDateTime) {
        LocalDateTime begin = LocalDateTime.of(localDateTime.toLocalDate(), LocalTime.MIN);
        return begin;
    }

    /**
     * 获取指定时间的23:59:59
     * @param localDateTime
     * @return
     */
    public static LocalDateTime getLocalDateTimeForEnd(LocalDateTime localDateTime) {
        LocalDateTime end = LocalDateTime.of(localDateTime.toLocalDate(), LocalTime.MAX);
        return end;
    }

    /**
     * 指定日期月的最后一天（yyyy-MM-dd）
     *
     * @param curDate 日期格式（yyyy-MM-dd）
     * @param firstOrLast true：第一天，false：最后一天
     * @return
     */
    public static String getLastDayOfMonth(String curDate, boolean firstOrLast) {
        if (firstOrLast) {
            return LocalDate.parse(curDate, yyyyMMdd_EN).with(TemporalAdjusters.firstDayOfMonth()).toString();
        } else {
            return LocalDate.parse(curDate, yyyyMMdd_EN).with(TemporalAdjusters.lastDayOfMonth()).toString();
        }
    }

    /**
     * 指定日期年的最后一天（yyyy-MM-dd）
     *
     * @param curDate 指定日期（格式：yyyy-MM-dd）
     * @param firstOrLast true:第一天，false:最后一天
     * @return
     */
    public static String getLastDayOfYear(String curDate, boolean firstOrLast) {
        if (firstOrLast) {
            return LocalDate.parse(curDate, yyyyMMdd_EN).with(TemporalAdjusters.firstDayOfYear()).toString();
        } else {
            return LocalDate.parse(curDate, yyyyMMdd_EN).with(TemporalAdjusters.lastDayOfYear()).toString();
        }
    }

    /**
     * 检查重复事件，比如生日。实现方法就是只比较月日
     * @return
     */
    public static boolean isBirthday(int month, int dayOfMonth) {
        MonthDay birthDay = MonthDay.of(month, dayOfMonth);
        MonthDay curMonthDay = MonthDay.from(LocalDate.now());// MonthDay只存储了月、日。
        if (birthDay.equals(curMonthDay)) {
            return true;
        }
        return false;
    }
    /**
     * 检测：输入年份是否是闰年？
     * @param date 日期格式：yyyy-MM-dd
     * @return true：闰年，false：平年
     */
    public static boolean isLeapYear(String date) {
        return LocalDate.parse(date.trim()).isLeapYear();
    }





    //补充的方法，比较两个时间哪个早，需要写throws ParseException。 a早于b返回true，否则返回false
    public static boolean compareDateTime(String time1,String time2) {
        //如果想比较日期则写成"yyyy-MM-dd"就可以了
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //将字符串形式的时间转化为Date类型的时间
        Date a =null;
        Date b = null;
        try {
            a = sdf.parse(time1);
            b = sdf.parse(time2);//抛出异常
        }catch (ParseException e) {
            e.printStackTrace();
        }

//　　　　　//方法一：
        //Date类的一个方法，如果a早于b返回true，否则返回false
        if(a.before(b))
            return true;
        else
            return false;

//　　　　　//方法二：
        /*
         * 如果你不喜欢用上面这个太流氓的方法，也可以根据将Date转换成毫秒
        if(a.getTime()-b.getTime()<0)
            return true;
        else
            return false;
        */
    }

    //补充的方法，比较两个时间哪个早，需要写throws ParseException。 a早于b返回false，否则返回true
    public static boolean compareDate(String time1,String time2) {
        //如果想比较日期则写成"yyyy-MM-dd"就可以了
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        //将字符串形式的时间转化为Date类型的时间
        Date a =null;
        Date b = null;
        try {
            a = sdf.parse(time1);
            b = sdf.parse(time2);//抛出异常
        }catch (ParseException e) {
            e.printStackTrace();
        }

//　　　　　//方法一：
        //Date类的一个方法，如果a早于b返回false，a晚于b返回true
        if(a.before(b))
            return false;
        else
            return true;

//　　　　　//方法二：
        /*
         * 如果你不喜欢用上面这个太流氓的方法，也可以根据将Date转换成毫秒
        if(a.getTime()-b.getTime()<0)
            return true;
        else
            return false;
        */
    }

    //改写。判断一个日期是否在一个时间段内。在的话，则返回true，否则返回false
//   public static boolean isInTimeRange(String time1,String startTime,String endTime) throws ParseException {
    public static boolean isInTimeRange(String time1,String startTime,String endTime)  {
        //如果想比较日期则写成"yyyy-MM-dd"就可以了
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //将字符串形式的时间转化为Date类型的时间
        Date myTime= null;
        Date start = null;
        Date end = null;
        try {
            myTime = sdf.parse(time1);
            start=sdf.parse(startTime);
            end=sdf.parse(endTime);
        } catch (ParseException e) {
            e.printStackTrace();
        }

//        方法一：
//        if(myTime.before(start)==false && myTime.before(end)==true){return true;}
//        else{return false;}'
        //晚于开始时间，且早于结束时间，说明在这个范围内，返回true
        if(myTime.getTime()-start.getTime()>=0 && myTime.getTime()-end.getTime()<=0){
           return true;
        }
        else{
            return false;
        }
    }

    //改写。判断一个日期是否在一个时间段内。在这之前返回1，在这中间返回2，在这后面返回3
    public static Integer isInTimeRange2(String time1,String startTime,String endTime)  {
        //如果想比较日期则写成"yyyy-MM-dd"就可以了
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//注意这里HH表示24小时，hh表示12小时
        //将字符串形式的时间转化为Date类型的时间
        Date myTime= null;
        Date start = null;
        Date end = null;
        try {
            myTime = sdf.parse(time1);
            start=sdf.parse(startTime);
            end=sdf.parse(endTime);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        //        方法一：
//        if(myTime.before(start)==false && myTime.before(end)==true){return true;}
//        else{return false;}'
//        System.out.println("函数里面mytime="+myTime.getTime()+";start="+start.getTime()+";end="+end.getTime());
//        if(myTime.getTime()-start.getTime()>=0 && myTime.getTime()-end.getTime()<=0){
        if(myTime.before(start)==false && myTime.before(end)){
            return 2;
        }
        else if(myTime.before(start)){
            return 1;
        }
        else {
            return 3;
        }
    }


    /*判断几天是周几*/
    public static Integer getDayOfWeek(){
        Calendar calendar = Calendar.getInstance();
        return calendar.get(DAY_OF_WEEK) - 1;
    }


    //如果是要用我自己补充的比较日期，需要加上throws Exception
    public static void main(String[] args){

        System.out.println("今天是周几："+DateUtil.getDayOfWeek());
//        String durationStr = new String("2021年3月25日 8:00-12:00,2021年4月2日 8:00-12:00,2021年4月5日 8:00-12:00,2021年4月29日 8:00-23:00");
//        String durationStr = new String("2021年4月21日 7:00-14:00");
//        Integer dijicike = getOfflineCourseAlreadyStudyNum(durationStr);
//        System.out.println("第几次课了："+dijicike);
//        Map<String,Object> map = isNowTimeInDuration(durationStr);
//        System.out.println("map="+map);

//        //course_class表的duration是否在日期内
////        String durantionStr = new String("2021年3月25日 8:00-12:00,2021年4月2日 8:00-12:00,2021年4月5日 8:00-12:00");
//        String durantionStr = new String("2021年4月21日 7:00-14:00");
//        String[] durationList = durantionStr.split(",");
////        System.out.println(durationList.length);
//        if(durationList.length>1){
//            //获取开始日期
//            String[] startList = durationList[0].split(" ");
//            String startTime = startList[0];
//            System.out.println("startTime="+startTime);
//            //获取结束日期
//            String[] endList = durationList[durationList.length-1].split(" ");
//            String endTime = endList[0];
//            System.out.println("endTime="+endTime);
//            //整合
//            String courseTime =startTime+"~"+endTime;
//
//            String startTimeDate = startTime.replace('年','-').replace('月','-').replace('日',' ');
//            String endTimeDate = endTime.replace('年','-').replace('月','-').replace('日',' ');
//            System.out.println("startDate="+startTimeDate+"; endDate="+endTimeDate);
//            String nowTime = getNowTime_EN();
//            Integer timeFlag = isInTimeRange2(nowTime,startTimeDate+"00:00:00",endTimeDate+"00:00:00");
//            System.out.println("timeFlag="+timeFlag);
//        }
//        if(durationList.length == 1){
//            String courseTime = durationList[0];
//            String[] startList = durationList[0].split(" ");
//            String startTime = startList[0];
//            String[] startHHMMList = startList[1].split("-");
//            String time1 = startHHMMList[0]+":00";
//            String time2 = startHHMMList[1]+":00";
//            String startTimeDate2 = startTime.replace('年','-').replace('月','-').replace('日',' ')+time1;
//            System.out.println("time1="+time1+";time2="+time2);
//            String endTimeDate2 = startTime.replace('年','-').replace('月','-').replace('日',' ')+time2;
//            System.out.println("只有一个时间段时，课程时间显示为："+courseTime);
//            String nowTime = getNowTime_EN();
//            Integer timeFlag2 = isInTimeRange2(nowTime,startTimeDate2,endTimeDate2);
//            System.out.println("nowTime="+nowTime+";startTime="+startTimeDate2+";endTime="+endTimeDate2+";timeFlag="+timeFlag2);
//        }


//        //1，判断优惠券是否在有效期内
//        System.out.println("现在时间是："+getNowTime_EN());
//        String nowTime = getNowTime_EN();
//        String timeRange = new String("2021-04-06~2021-12-21");
//        String[] timeRange2= timeRange.split("~");
//        System.out.println("优惠券开始时间是："+timeRange2[0]+";过期时间是："+timeRange2[1]);//选择第2个元素
//        //1.2比较两个日期
//        boolean result=new DateUtil().isInTimeRange(nowTime,timeRange2[0]+" 00:00:00",timeRange2[1]+" 00:00:00");//a早于b返回true，否则返回false
//        System.out.println("是否在优惠券有效期内："+result);
//        System.out.println("===================");

        // String curDate = "2019-04-10"; // 指定日期
        // System.out.println(getLastDayOfMonth(curDate, true));
        // System.out.println(getLastDayOfMonth(curDate, false));
        // System.out.println(getLastDayOfYear(curDate, true));
        // System.out.println(getLastDayOfYear(curDate, false));
        // System.out.println("===================");
        // String startDate = "2019-02-28", endDate = "2019-03-05", period = DAY;
        // System.out.println(getPieDateRange(startDate, endDate, period));
        // System.out.println("===================");
        // System.out.println(getNextWeekDate("2019-02-28", 1, false));
        // System.out.println(getPieDateRange("2019-12-28", "2020-03-01", DAY));
        // System.out.println("===================");
        // System.out.println(getFirstOrLastWeekDate("2019-04-02", 0, false));
        // System.out.println(getPreWeekDate("2019-04-02", 2, false));
        // System.out.println(getNextWeekDate("2019-04-02", 2, false));
        // System.out.println("===================");
        // System.out.println("当前时间戳：" + Instant.now());
        // System.out.println("当前时间：" + LocalDateTime.now());
        // System.out.println("===================");
        // System.out.println(peridCount("2019-01-30", "2019-03-31", MONTH));
        // System.out.println(isLeapYear("2019-03-31"));
        // System.out.println(LocalDate.now().isLeapYear());
        // System.out.println("===================");
        // System.out.println(getAfterOrPreDate("2019-03-31", WEEK, -1));
        // System.out.println(getAfterOrPreDayDate(-5));
        // System.out.println(getAfterOrPreDayDate(-3));
        // System.out.println(getAfterOrPreDayDate(6));
        // System.out.println(getAfterOrPreYearDate(6));
        // System.out.println(getAfterOrPreWeekDate(1));
        // System.out.println("===================");
        // clock();
        // isBirthday(7, 13);
        // LocalDate date0 = LocalDate.of(2019, Month.OCTOBER, 31);
        // LocalDate date = LocalDate.of(2019, 3, 31);
        // System.out.println(date0.equals(LocalDate.now()));
        // System.out.println(date.getYear() + "-" + date.getMonthValue() + "-" + date.getDayOfMonth());
        // System.out.println(getNowTime_EN());
        // System.out.println(getAfterNowTimeSimp(SECOND, 5L));
        // System.out.println("===================");
        // System.out.println(getAfterNowTime(SECOND, 5L));
        // System.out.println(getAfterNowTimePlus(yyyyMMddHHmm_EN, SECOND, 5L));
        // System.out.println("===================");
        // System.out.println(getNowDate_EN());
        // System.out.println(getNowDate_CN());
        // System.out.println(getTime("HH:mm:ss"));
        // System.out.println(getNowTime_EN());
        // System.out.println(getNowTime_CN());
        // System.out.println(getNowLocalTime_shot());
        // System.out.println(getNowLocalTime_full());
        // System.out.println(getNowLocalTime_long());
        // System.out.println(getNowLocalTime_medium());
        // System.out.println(getNodeTime("week"));
        // System.out.println(transformWeekEN2Num(null));
        // System.out.println("===================");
    }

}

